package com.ct.boss.demo.advice;

import com.alibaba.fastjson.JSON;
import com.ct.boss.demo.exception.BusinessException;
import com.ct.boss.demo.http.HttpResult;
import com.ct.boss.demo.http.HttpStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @author ChenTong
 * @version 1.0
 * @description 异常处理
 * @date 2020/6/15 21:59
 * @modified
 **/
@ControllerAdvice
@ResponseBody
@Slf4j
public class ExceptionHandlerAdvice implements ResponseBodyAdvice {

    private ThreadLocal<Object> modelHolder = new ThreadLocal<>();

    //参数验证失败，抛出异常处理
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public HttpResult handleIllegalParamException(MethodArgumentNotValidException e) {
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        String tips = "参数不合法";
        if (!errors.isEmpty()) {
            tips = errors.get(0).getDefaultMessage();
        }
        return HttpResult.error(tips, HttpStatus.PARAMETER_ERROR.getCode());
    }

    @ExceptionHandler(BindException.class)
    public HttpResult handleIllegalParamException(BindException e) {
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        String tips = "参数绑定失败";
        if (!errors.isEmpty()) {
            tips = errors.get(0).getDefaultMessage();
        }
        return HttpResult.error(tips, HttpStatus.PARAMETER_ERROR.getCode());
    }

    //resultException处理
    @ExceptionHandler(BusinessException.class)
    public HttpResult handleResultException(BusinessException e, HttpServletRequest request) {
        log.debug("uri={} | requestBody={}", request.getRequestURI(),
                JSON.toJSONString(modelHolder.get()));
        return HttpResult.error("业务逻辑异常",e.getCode());
    }

    //网络异常
    @ExceptionHandler(Exception.class)
    public HttpResult handleException(Exception e, HttpServletRequest request) {
        log.error("uri={} | requestBody={}", request.getRequestURI(),
                JSON.toJSONString(modelHolder.get()), e);
        return HttpResult.error("网络异常",HttpStatus.NETWORK_ERROR.getCode());
    }

    @InitBinder
    public void initBinder(WebDataBinder webDataBinder) {
        // ModelHolder 初始化
        modelHolder.set(webDataBinder.getTarget());
    }

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // ModelHolder 清理
        modelHolder.remove();
        return body;
    }
}
